#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>






#include "genserver.h"

#define PORT            (9734)
#define HEADRSIZE       (4)
#define EXPTMESSIZE     (10)


int numofrecivemess;
int numofclients;
int numofsendmessages;


/*************Need for TCP TESTS*************************************************/
int RI=0;

int numofclients;
int    flag =0;
typedef struct application_t
{
    GenSv*      m_sv;
}appl;

struct argum_t
{
    char     filename1[200];
    char     filename2[200];
    char     filename3[200];
    GenSv*   sv;
};

/*Global variables*********************************************************/
char** argv;
int    IDcont;
int    loop=0;
/*********CallBackFunction************************************************/
/* 1st 4 bytes in each meassage*/
size_t Headrfunc(void* _buf)
{
    return *((size_t*) _buf);
}
/*************************Taskfunction*************************************************************/

void printClients(void* _data)
{
    printf("Number of connected clients : %d ", *(int*)_data);
    return;
}

void printWriten(void* _data)
{
    printf("Number of writed messages : %d ", *(int*)_data);
    return;
}

void printReaden(void* _data)
{
    printf("Number of readen messages : %d ", *(int*)_data);
    return;
}

/*CallBackFunction***********************************************************************/
void NewClient(int _idclient,void* _app)
{
    FILE*    fp =0;
    char   text[50];

    printf("\nNewClientCALLBACK , id : %d",_idclient);
    fflush(stdout);

    fp = fopen(argv[3],"r");
    if (fp!=(void*)0 && fp!=(void*)-1)
    {
        fgets(text,50,fp);

    }
    if (fp)
    {
        fclose(fp);
    }

    if (! strcmp(argv[3],text) )/*Determined the client to can write*/
    {
        IDcont = _idclient;
    }

    ++numofclients;

    return;
}


void NewMessage(int _IDclient,void* _app, void*  _buf,size_t _mesSize)
{
    char*  answer1={"\nSharikPriloharik\n"};
    char*  answer2={"\nKam Tsu Mir\n"};

   if ( IDcont == _IDclient)
    {
        printf("\nServer send Message to client ID %d\n",_IDclient);
        if (loop%2)
        {
            GsvServerWrite(((appl*)_app)->m_sv,_IDclient,answer1,strlen(answer1)+1);
        }
        else
        {
            GsvServerWrite(((appl*)_app)->m_sv,_IDclient,answer2,strlen(answer2)+1);
            GsvServerWrite(((appl*)_app)->m_sv,_IDclient,answer2,strlen(answer2)+1);
            GsvServerWrite(((appl*)_app)->m_sv,_IDclient,answer2,strlen(answer2)+1);
        }
        ++loop;

        if( loop > 40000)
        {
            printf("\n!!!!Server ORDER to disconnect the user with ID  %d  :\n!!!!!",_IDclient);
            GsvServerDrop(((appl*)_app)->m_sv,_IDclient);
        }
        ++numofsendmessages;
    }
    else
    {
        ++numofrecivemess;
    }

     printf("\n Message recieved from\
     client ID %d  : %s \n", _IDclient, (char*)_buf+4);
     fflush(stdout);

    return;
}

void NewExeption(int _IDclient,void* _app, void*  _buf,size_t _mesSize)
{
    printf("Exeption message arrived from client\
    ID %d was %s :\n",_IDclient, (char*)_buf+4);
}

void ClientDiscn(int _IDclient,void* _app,size_t _notreaded,size_t _notwrited)
{
    printf("\n Problem with client ID %d ,\
      \n%d bytes remain _not readed and %d remain not writed \n", _IDclient,_notreaded,_notwrited);
     return;
}
/******************************************************************************/

void regression_test();

int  unitest_CreateandRun();
int  unitest_ClientConnectandRecieve();
int  unitest_Scheduller();

static void* ServerRun(void* _arg);
static void* ServerStop(void* _arg);
static void* ServerDelete(void* _arg);
static void* RunClient(void* _arg);

int main(int _argc, char* _argv[])
{
    argv = (char**)_argv;/*initillize the global const*/
    printf( "\nargument number are : %d " ,  _argc);
    while(_argc--)
    {
        printf( "\nthe argements are : %s ", *((_argv)++));
    }
    regression_test();
    return 0;
}

void regression_test()
{
   /* printf("\ncreate and run are started");
    fflush(stdout);
    unitest_CreateandRun();
    printf("\nConnect and Reciev are started\n");
    fflush(stdout);
    unitest_ClientConnectandRecieve();
    printf("\nScheduller testing started\n");
    fflush(stdout);*/
    unitest_Scheduller();
}

int  unitest_CreateandRun()
{
        appl*               app=(appl*)malloc(sizeof(appl));
        pthread_t           thread[3];
        struct argum_t      argum[3];
        int                 childID;

        if ((childID =fork()) == 0)
        {
            GenSv*      sv = GsvServerNew(PORT,app,HEADRSIZE,
            Headrfunc,NewClient,NewMessage,ClientDiscn,
            EXPTMESSIZE,NewExeption);
            app->m_sv=sv;
            argum[0].sv = sv;

            pthread_create( &thread[0], NULL,ServerRun,(void*)&argum[0]);

            sleep(1);/*Deremined the tester work time*/

            printf("\nRun time is finished, Sever Stop\n");
            pthread_create( &thread[1], NULL,ServerStop,(void*)&argum[0]);
            sleep(1);
            printf("\nDelete Server\n");
            pthread_create( &thread[2], NULL,ServerDelete,(void*)&argum[0]);
            sleep(1);
            pthread_join(thread[2], NULL);
            pthread_join(thread[1], NULL);
            pthread_join(thread[0], NULL);
            printf("\nServer Deleted\n");
            fflush(stdout);
            exit(0);
        }
        wait(0);
        return 0;

}

int  unitest_ClientConnectandRecieve()
{
    appl*               app=(appl*)malloc(sizeof(appl));
    pthread_t           thread[4];
    struct argum_t      argum[4];

    GenSv*              sv = GsvServerNew(PORT,app,HEADRSIZE,
    Headrfunc,NewClient,NewMessage,ClientDiscn,
    EXPTMESSIZE,NewExeption);
    app->m_sv=sv;
    argum[0].sv = sv;

    pthread_create( &thread[0], NULL,ServerRun,(void*)&argum[0]);
    sleep(1);/*Deremined the tester work time*/
    pthread_create( &thread[1], NULL,RunClient,(void*)&argum[0]);
    sleep(15);/*Deremined the tester work time*/

    printf("\nRun time is finished, Sever Stop\n");
    pthread_create( &thread[2], NULL,ServerStop,(void*)&argum[0]);
    sleep(1);
    printf("\nDelete Server\n");
    pthread_create( &thread[3], NULL,ServerDelete,(void*)&argum[0]);
    sleep(1);
    pthread_join(thread[3], NULL);
    pthread_join(thread[2], NULL);
    pthread_join(thread[1], NULL);
    pthread_join(thread[0], NULL);
    return 0;
}

int  unitest_Scheduller()
{
    pthread_t           thread[4];
    struct argum_t      argum[4];

    appl*     app=(appl*)malloc(sizeof(appl));
    GenSv*      sv = GsvServerNew(PORT,app,HEADRSIZE,
        Headrfunc,NewClient,NewMessage,ClientDiscn,
        EXPTMESSIZE,NewExeption);
    app->m_sv = sv;
    app->m_sv=sv;
    argum[0].sv = sv;

    numofclients=0;
    numofrecivemess =0;

    numofsendmessages =0;

    GsvSchedullerAddTask(sv,printWriten, 2000,&numofclients);
    GsvSchedullerAddTask(sv,printClients,5000,&numofrecivemess);
    GsvSchedullerAddTask(sv,printReaden, 4000,&numofsendmessages);


    pthread_create( &thread[0], NULL,ServerRun,(void*)&argum[0]);
    sleep(1);/*Deremined the tester work time*/
    pthread_create( &thread[1], NULL,RunClient,(void*)&argum[0]);
    sleep(300);/*Deremined the tester work time*/

    printf("\nRun time is finished, Sever Stop\n");
    pthread_create( &thread[2], NULL,ServerStop,(void*)&argum[0]);
    sleep(1);
    printf("\nDelete Server\n");
    pthread_create( &thread[3], NULL,ServerDelete,(void*)&argum[0]);
    sleep(1);
    pthread_join(thread[3], NULL);
    pthread_join(thread[2], NULL);
    pthread_join(thread[1], NULL);
    pthread_join(thread[0], NULL);

    return 0;
}



/*Threads implementations*/
static void* ServerRun(void* _arg)
{
    struct argum_t*    argum =(struct argum_t*) _arg;
    GsvServerRun(argum->sv);
    return (void*)0;
}

static void* ServerStop(void* _arg)
{
    struct argum_t*    argum =(struct argum_t*) _arg;
    GsvServerStop(argum->sv);
    return (void*)0;
}

static void* ServerDelete(void* _arg)
{
    struct argum_t*    argum =(struct argum_t*) _arg;
    GsvServerDelete(argum->sv);
    return (void*)0;
}

static void* RunClient(void* _arg)
{
    int    childeID;

   childeID = fork();
    if (childeID == 0)
    {
        execve(argv[1],argv,0);
    }
    sleep(2);
    childeID = fork();
    if (childeID == 0)
    {
        execve(argv[2],argv,0);
    }
    return (void*)0;
}


